package main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"sync"
)

const (
	version string = "0.0.1"
)

var (
	listenAddr string
	rooms      sync.Map
	conn       *net.UDPConn
)

func main() {
	flag.StringVar(&listenAddr, "l", ":9999", "listen address")
	flag.Parse()

	log.Println("Version", version)
	log.Println("Receiving on", listenAddr)

	addr, err := net.ResolveUDPAddr("udp", listenAddr)
	if err != nil {
		fmt.Println("[ERROR]", err)
		return
	}

	conn, err = net.ListenUDP("udp", addr)
	if err != nil {
		fmt.Println("[ERROR]", err)
		return
	}

	for {
		request := make([]byte, 64)
		_, remoteAddr, err := conn.ReadFromUDP(request)
		if err != nil {
			fmt.Println("[WARN]", err)
			continue
		}
		log.Printf("FROM %s RECEIVED %s\n", remoteAddr.String(), string(request))

		go handlePacket(remoteAddr, request)
	}
}

func handlePacket(from *net.UDPAddr, request []byte) {
	var response []byte

	rid := string(request) // room id
	v, ok := rooms.Load(rid)

	if !ok {
		log.Printf("CREATE room '%s'", rid)
		rooms.Store(rid, from.String())
	} else {
		if v.(string) == from.String() {
			return
		} else {
			addr, err := net.ResolveUDPAddr("udp", v.(string))
			if err != nil {
				response = []byte("0.0.0.0:0")
			} else {
				response = []byte(v.(string))
			}
			_, err = conn.WriteToUDP([]byte(from.String()), addr)
			if err != nil {
				log.Println("[WARN] WriteToUDP()", err, addr)
			}
			_, err = conn.WriteToUDP(response, from)
			if err != nil {
				log.Println("[WARN] WriteToUDP()", err, from)
			}

			log.Printf("DELETE room '%s'", rid)
			rooms.Delete(rid)
		}
	}
}
